package cinvestment;

import ilog.concert.IloLinearNumExpr;
import ilog.concert.IloNumVar;
import ilog.cplex.IloCplex;

import java.util.List;
import util.NullOutputStream;
import concurrent.Job;

public class DualSolver extends Job<DualResult> {
	private double[] demand;
	private double[] K;
	private int N;
	private int n;
	private double[] penalty;
	private List<Plant> plants;

	private int taskIndex = 0;

	public DualSolver(int N, int n, double[] demand, double[] K,
			double[] penalty, List<Plant> plants, int ti) {
		this.N = N;
		this.n = n;
		this.demand = demand;
		this.K = K;
		this.penalty = penalty;
		this.plants = plants;
		this.taskIndex = ti;
	}

	@Override
	public DualResult execute() {
		DualResult result = new DualResult();
		try {
			IloCplex cplex = new IloCplex();
			cplex.setOut(new NullOutputStream());

			IloNumVar[] pi = cplex
					.numVarArray(N, Double.NEGATIVE_INFINITY, 0.0);
			IloNumVar[] sigma = cplex.numVarArray(n, Double.NEGATIVE_INFINITY,
					0.0);

			IloLinearNumExpr obj = cplex.linearNumExpr();
			obj.add(cplex.scalProd(demand, pi));
			obj.add(cplex.scalProd(K, sigma));
			cplex.addMaximize(obj);

			for (int i = 0; i < N; i++) {
				for (int j = 0; j < n; j++) {
					if (this.isArcInConfiguration(i, j))
						cplex.addLe(cplex.sum(pi[i], sigma[j]),
								-this.penalty[i]);
				}
			}

			// cplex.exportModel(Lang.projectRoot() + "\\data\\dual\\dual_"
			// + this.taskIndex + ".lp");

			if (cplex.solve()) {
				double[] pi_value = cplex.getValues(pi);
				double[] sigma_value = cplex.getValues(sigma);
				double et = 0.0;
				double Etk = 0.0;
				for (int i = 0; i < N; i++)
					et += demand[i] * pi_value[i];

				for (int j = 0; j < n; j++) {
					Etk += -K[j] * sigma_value[j];
				}
				result.setEt(sigma_value);
				result.setEtk(Etk);
				result.setEtm(et);
				result.setLambda(sigma_value);
				result.setObjValue(cplex.getObjValue());
			}
			cplex.end();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	private boolean isArcInConfiguration(int i, int j) {

		return plants.get(j).isAvailable(i);
	}

}
